package com.dddframework.core.utils;

import cn.hutool.core.util.StrUtil;
import com.dddframework.core.contract.IR;
import com.dddframework.core.contract.enums.ResultCode;
import com.dddframework.core.contract.exception.ServiceException;

import java.util.function.Supplier;

/**
 * 业务断言类，断言不通过将抛出ServiceException
 */
public class BizAssert {
    /**
     * 断言是否为真，如果为 {@code false} 抛出给定的异常<br>
     *
     * <pre class="code">
     * Assert.isTrue(i &gt; 0, ServiceException::new);
     * </pre>
     *
     * @param <X>         异常类型
     * @param expect      布尔值
     * @param falseThrow 指定断言不通过时抛出的异常
     * @throws X if expect is {@code false}
     */
    public static <X extends Throwable> void isTrue(Boolean expect, Supplier<? extends X> falseThrow) throws X {
        if (!expect) {
            throw falseThrow.get();
        }
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出给定的异常<br>
     *
     * <pre class="code">
     * Assert.isFalse(i &gt; 0, ServiceException::new);
     * </pre>
     *
     * @param <X>         异常类型
     * @param unexpect    布尔值
     * @param trueThrow 指定断言不通过时抛出的异常
     * @throws X if unexpect is {@code true}
     */
    public static <X extends Throwable> void isFalse(Boolean unexpect, Supplier<? extends X> trueThrow) throws X {
        if (unexpect) {
            throw trueThrow.get();
        }
    }

    public static void isTrue(Boolean expect, Integer code, String falseThrow, Object... params) {
        if (!expect) {
            throw new ServiceException(code, StrUtil.format(falseThrow, params));
        }
    }

    public static void isTrue(Boolean expect, String falseThrow, Object... params) {
        if (!expect) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(falseThrow, params));
        }
    }

    public static void isFalse(Boolean unexpect, Integer code, String trueThrow, Object... params) {
        if (unexpect) {
            throw new ServiceException(code, StrUtil.format(trueThrow, params));
        }
    }

    public static void isFalse(Boolean unexpect, String trueThrow, Object... params) {
        if (unexpect) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(trueThrow, params));
        }
    }

    public static <T> T notNull(T dontNull, Integer code, String nullThrow, Object... params) {
        if (dontNull == null) {
            throw new ServiceException(code, StrUtil.format(nullThrow, params));
        }
        return dontNull;
    }

    public static <T> T notNull(T dontNull, String nullThrow, Object... params) {
        if (dontNull == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(nullThrow, params));
        }
        return dontNull;
    }

    public static <T> T notNull(T dontNull) {
        if (dontNull == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this object must not be null");
        }
        return dontNull;
    }

    public static <T> void isNull(T nullVal, Integer code, String notNullThrow, Object... params) {
        if (nullVal != null) {
            throw new ServiceException(code, StrUtil.format(notNullThrow, params));
        }
    }

    public static <T> void isNull(T nullVal, String notNullThrow, Object... params) {
        if (nullVal != null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(notNullThrow, params));
        }
    }

    public static <T> void isNull(T nullVal) {
        if (nullVal != null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this object must be null");
        }
    }

    public static void notBlank(String dontBlank, Integer code, String blankThrow, Object... params) {
        if (dontBlank == null || dontBlank.length() == 0) {
            throw new ServiceException(code, StrUtil.format(blankThrow, params));
        }
    }

    public static void notBlank(String dontBlank, String blankThrow, Object... params) {
        if (dontBlank == null || dontBlank.length() == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(blankThrow, params));
        }
    }

    public static void notBlank(String dontBlank) {
        if (dontBlank == null || dontBlank.length() == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this string must not be null or blank");
        }
    }

    public static void isBlank(String blankVal, Integer code, String notBlankThrow, Object... params) {
        if (blankVal != null && blankVal.length() != 0) {
            throw new ServiceException(code, StrUtil.format(notBlankThrow, params));
        }
    }

    public static void isBlank(String blankVal, String notBlankThrow, Object... params) {
        if (blankVal != null && blankVal.length() != 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(notBlankThrow, params));
        }
    }

    public static void isBlank(String blankVal) {
        if (blankVal != null && blankVal.length() != 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this string must be null or blank");
        }
    }

    public static <E, T extends Iterable<E>> T notEmpty(T dontEmpty, Integer code, String emptyThrow, Object... params) {
        if (dontEmpty == null || !dontEmpty.iterator().hasNext()) {
            throw new ServiceException(code, StrUtil.format(emptyThrow, params));
        }
        return dontEmpty;
    }

    public static <E, T extends Iterable<E>> T notEmpty(T dontEmpty, String emptyThrow, Object... params) {
        if (dontEmpty == null || !dontEmpty.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(emptyThrow, params));
        }
        return dontEmpty;
    }

    public static <E, T extends Iterable<E>> T notEmpty(T dontEmpty) {
        if (dontEmpty == null || !dontEmpty.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this collection must not be null or empty");
        }
        return dontEmpty;
    }

    public static <E, T extends Iterable<E>> void isEmpty(T emptyVal, Integer code, String notEmptyThrow, Object... params) {
        if (emptyVal != null && emptyVal.iterator().hasNext()) {
            throw new ServiceException(code, StrUtil.format(notEmptyThrow, params));
        }
    }

    public static <E, T extends Iterable<E>> void isEmpty(T emptyVal, String notEmptyThrow, Object... params) {
        if (emptyVal != null && emptyVal.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(notEmptyThrow, params));
        }
    }

    public static <E, T extends Iterable<E>> void isEmpty(T emptyVal) {
        if (emptyVal != null && emptyVal.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this collection must not be null or empty");
        }
    }

    public static <T> T[] notEmpty(T[] dontEmpty, Integer code, String emptyThrow, Object... params) {
        if (dontEmpty == null || dontEmpty.length == 0) {
            throw new ServiceException(code, StrUtil.format(emptyThrow, params));
        }
        return dontEmpty;
    }

    public static <T> T[] notEmpty(T[] objects, String emptyThrow, Object... params) {
        if (objects == null || objects.length == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(emptyThrow, params));
        }
        return objects;
    }

    public static <T> T[] notEmpty(T[] dontEmpty) {
        if (dontEmpty == null || dontEmpty.length == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this arrays must not be null or empty");
        }
        return dontEmpty;
    }

    public static <T> T[] isEmpty(T[] emptyVal, Integer code, String notEmptyThrow, Object... params) {
        if (emptyVal == null || emptyVal.length != 0) {
            throw new ServiceException(code, StrUtil.format(notEmptyThrow, params));
        }
        return emptyVal;
    }

    public static <T> void isEmpty(T[] emptyVal, String notEmptyThrow, Object... params) {
        if (emptyVal == null || emptyVal.length != 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(notEmptyThrow, params));
        }
    }

    public static <T> void isEmpty(T[] emptyVal) {
        if (emptyVal == null || emptyVal.length != 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this arrays must be null or empty");
        }
    }

    public static <T> T isOk(IR r, Integer code, String notOkThrow, Object... params) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(code, StrUtil.format(notOkThrow, params));
        }
        return r.getData();
    }

    public static <T> T isOk(IR r, String notOkThrow, Object... params) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(notOkThrow, params));
        }
        return r.getData();
    }

    public static <T> T isOk(IR r, Supplier<String> notOk) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), notOk.get());
        }
        return r.getData();
    }

    public static <T> T isOk(IR r) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), r == null ? "this result must not be null" : r.getMsg());
        }
        return r.getData();
    }

    public static <T> T notNull(IR r, Integer code, String dataNullThrow, Object... params) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(code, StrUtil.format(dataNullThrow, params));
        }
        return r.getData();
    }

    public static <T> T notNull(IR r, String dataNullThrow, Object... params) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(dataNullThrow, params));
        }
        return r.getData();
    }

    public static <T> T notNull(IR r, Supplier<String> dataNull) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), dataNull.get());
        }
        return r.getData();
    }

    public static <T> T notNull(IR r) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), r == null ? "this result must not be null" : r.getMsg());
        }
        return r.getData();
    }

}
